package eu.catengine.renderable.sprite;

import javax.microedition.khronos.opengles.GL10;

import eu.catengine.common.iface.ISprite;
import eu.catengine.graphic.Texture;
import eu.catengine.graphic.TextureRegion;
import eu.catengine.primitive.Point;
import eu.catengine.primitive.Size;
import eu.catengine.renderable.shape.Rectangle;

/**
 * Klasa przechowująca dane dotyczące sprite'a wyświetlanego w scenie. <br>
 * <br>
 * Punt zaczepienia obiektu (anchor point) znajduje się w lewym górnym rogu.
 * 
 * @author mbienkowski
 */
public class Sprite extends Rectangle implements ISprite
{
    protected Texture mTexture;
    protected TextureRegion mTextureRegion;

    protected Sprite()
    {
	super(null, null);
    }

    /**
     * Tworzy dwuwymiarowy obraz z tekstury.
     * 
     * @param point
     *            <code>Point</code> Punkt zaczepienia.
     * @param texture
     *            <code>Texture</code> Tekstura pobrana z TextureManager.
     */
    public Sprite(Point point, Texture texture)
    {
	super("", point.x, point.y, texture.getSize().width,
		texture.getSize().height);
	this.setSpriteData(texture, "default");
    }

    /**
     * Tworzy dwuwymiarowy obraz z tekstury.
     * 
     * @param x
     *            <code>float</code> Współrzędna X punktu zaczepienia.
     * @param y
     *            <code>float</code> Współrzędna Y punktu zaczepienia.
     * @param texture
     *            <code>Texture</code> Tekstura pobrana z TextureManager.
     */
    public Sprite(float x, float y, Texture texture)
    {
	super("", x, y, texture.getSize().width, texture.getSize().height);
	this.setSpriteData(texture, "default");
    }

    /**
     * Tworzy dwuwymiarowy obraz z tekstury.
     * 
     * @param point
     *            <code>Point</code> Punkt zaczepienia.
     * @param size
     *            <code>Size</code> Rozmiar obiektu.
     * @param texture
     *            <code>Texture</code> Tekstura pobrana z TextureManager.
     */
    public Sprite(Point point, Size size, Texture texture)
    {
	super("", point.x, point.y, texture.getSize().width,
		texture.getSize().height);
	this.setSpriteData(texture, "default");
    }

    /**
     * Tworzy dwuwymiarowy obraz z tekstury.
     * 
     * @param x
     *            <code>float</code> Współrzędna X punktu zaczepienia.
     * @param y
     *            <code>float</code> Współrzędna Y punktu zaczepienia.
     * @param size
     *            <code>Size</code> Rozmiar obiektu.
     * @param texture
     *            <code>Texture</code> Tekstura pobrana z TextureManager.
     */
    public Sprite(float x, float y, Size size, Texture texture)
    {
	super("", x, y, texture.getSize().width, texture.getSize().height);
	this.setSpriteData(texture, "default");
    }

    /**
     * Tworzy dwuwymiarowy obraz z tekstury.
     * 
     * @param x
     *            <code>float</code> Współrzędna X punktu zaczepienia.
     * @param y
     *            <code>float</code> Współrzędna Y punktu zaczepienia.
     * @param width
     *            <code>float</code> Szerokość.
     * @param height
     *            <code>float</code> Wysokość.
     * @param texture
     *            <code>Texture</code> Tekstura pobrana z TextureManager.
     */
    public Sprite(float x, float y, float width, float height, Texture texture)
    {
	super("", x, y, width, height);
	this.setSpriteData(texture, "default");
    }

    /**
     * Tworzy dwuwymiarowy obraz z tekstury.
     * 
     * @param point
     *            <code>Point</code> Punkt zaczepienia.
     * @param texture
     *            <code>Texture</code> Tekstura pobrana z TextureManager.
     * @param textureRegionID
     *            <code>String</code> Nazwa regionu tekstury, który ma się
     *            wyświetlić.
     * 
     */
    public Sprite(Point point, Texture texture, String textureRegionID)
    {
	super("", point.x, point.y, texture.getTextureRegion(textureRegionID)
		.getSize().width, texture.getTextureRegion(textureRegionID)
		.getSize().height);
	this.setSpriteData(texture, textureRegionID);
    }

    /**
     * Tworzy dwuwymiarowy obraz z tekstury.
     * 
     * @param x
     *            <code>float</code> Współrzędna X punktu zaczepienia.
     * @param y
     *            <code>float</code> Współrzędna Y punktu zaczepienia.
     * @param texture
     *            <code>Texture</code> Tekstura pobrana z TextureManager.
     * @param textureRegionID
     *            <code>String</code> Nazwa regionu tekstury, który ma się
     *            wyświetlić.
     */
    public Sprite(float x, float y, Texture texture, String textureRegionID)
    {
	super("", x, y,
		texture.getTextureRegion(textureRegionID).getSize().width,
		texture.getTextureRegion(textureRegionID).getSize().height);
	this.setSpriteData(texture, textureRegionID);
    }

    /**
     * Tworzy dwuwymiarowy obraz z tekstury.
     * 
     * @param point
     *            <code>Point</code> Punkt zaczepienia.
     * @param size
     *            <code>Size</code> Rozmiar obiektu.
     * @param texture
     *            <code>Texture</code> Tekstura pobrana z TextureManager.
     * @param textureRegionID
     *            <code>String</code> Nazwa regionu tekstury, który ma się
     *            wyświetlić.
     */
    public Sprite(Point point, Size size, Texture texture,
	    String textureRegionID)
    {
	super("", point.x, point.y, size.width, size.height);
	this.setSpriteData(texture, textureRegionID);
    }

    /**
     * Tworzy dwuwymiarowy obraz z tekstury.
     * 
     * @param x
     *            <code>float</code> Współrzędna X punktu zaczepienia.
     * @param y
     *            <code>float</code> Współrzędna Y punktu zaczepienia.
     * @param size
     *            <code>Size</code> Rozmiar obiektu.
     * @param texture
     *            <code>Texture</code> Tekstura pobrana z TextureManager.
     * @param textureRegionID
     *            <code>String</code> Nazwa regionu tekstury, który ma się
     *            wyświetlić.
     */
    public Sprite(float x, float y, Size size, Texture texture,
	    String textureRegionID)
    {
	super("", x, y, size.width, size.height);
	this.setSpriteData(texture, textureRegionID);
    }

    /**
     * Tworzy dwuwymiarowy obraz z tekstury.
     * 
     * @param x
     *            <code>float</code> Współrzędna X punktu zaczepienia.
     * @param y
     *            <code>float</code> Współrzędna Y punktu zaczepienia.
     * @param width
     *            <code>float</code> Szerokość.
     * @param height
     *            <code>float</code> Wysokość.
     * @param texture
     *            <code>Texture</code> Tekstura pobrana z TextureManager.
     * @param textureRegionID
     *            <code>String</code> Nazwa regionu tekstury, który ma się
     *            wyświetlić.
     */
    public Sprite(float x, float y, float width, float height, Texture texture,
	    String textureRegionID)
    {
	super("", x, y, width, height);
	this.setSpriteData(texture, textureRegionID);
    }

    /**
     * Tworzy dwuwymiarowy obraz z tekstury.
     * 
     * @param id
     *            <code>String</code> Nazwa obiektu.
     * @param point
     *            <code>Point</code> Punkt zaczepienia.
     * @param texture
     *            <code>Texture</code> Tekstura pobrana z TextureManager.
     */
    public Sprite(String id, Point point, Texture texture)
    {
	super(id, point.x, point.y, texture.getSize().width,
		texture.getSize().height);
	this.setSpriteData(texture, "default");
    }

    /**
     * Tworzy dwuwymiarowy obraz z tekstury.
     * 
     * @param id
     *            <code>String</code> Nazwa obiektu.
     * @param x
     *            <code>float</code> Współrzędna X punktu zaczepienia.
     * @param y
     *            <code>float</code> Współrzędna Y punktu zaczepienia.
     * @param texture
     *            <code>Texture</code> Tekstura pobrana z TextureManager.
     */
    public Sprite(String id, float x, float y, Texture texture)
    {
	super(id, x, y, texture.getSize().width, texture.getSize().height);
	this.setSpriteData(texture, "default");
    }

    /**
     * Tworzy dwuwymiarowy obraz z tekstury.
     * 
     * @param id
     *            <code>String</code> Nazwa obiektu.
     * @param point
     *            <code>Point</code> Punkt zaczepienia.
     * @param size
     *            <code>Size</code> Rozmiar obiektu.
     * @param texture
     *            <code>Texture</code> Tekstura pobrana z TextureManager.
     */
    public Sprite(String id, Point point, Size size, Texture texture)
    {
	super(id, point.x, point.y, size.width, size.height);
	this.setSpriteData(texture, "default");
    }

    /**
     * Tworzy dwuwymiarowy obraz z tekstury.
     * 
     * @param id
     *            <code>String</code> Nazwa obiektu.
     * @param x
     *            <code>float</code> Współrzędna X punktu zaczepienia.
     * @param y
     *            <code>float</code> Współrzędna Y punktu zaczepienia.
     * @param size
     *            <code>Size</code> Rozmiar obiektu.
     * @param texture
     *            <code>Texture</code> Tekstura pobrana z TextureManager.
     */
    public Sprite(String id, float x, float y, Size size, Texture texture)
    {
	super(id, x, y, size.width, size.height);
	this.setSpriteData(texture, "default");
    }

    /**
     * Tworzy dwuwymiarowy obraz z tekstury.
     * 
     * @param id
     *            <code>String</code> Nazwa obiektu.
     * @param x
     *            <code>float</code> Współrzędna X punktu zaczepienia.
     * @param y
     *            <code>float</code> Współrzędna Y punktu zaczepienia.
     * @param width
     *            <code>float</code> Szerokość.
     * @param height
     *            <code>float</code> Wysokość.
     * @param texture
     *            <code>Texture</code> Tekstura pobrana z TextureManager.
     */
    public Sprite(String id, float x, float y, float width, float height,
	    Texture texture)
    {
	super(id, x, y, width, height);
	this.setSpriteData(texture, "default");
    }

    /**
     * Tworzy dwuwymiarowy obraz z tekstury.
     * 
     * @param id
     *            <code>String</code> Nazwa obiektu.
     * @param point
     *            <code>Point</code> Punkt zaczepienia.
     * @param texture
     *            <code>Texture</code> Tekstura pobrana z TextureManager.
     * @param textureRegionID
     *            <code>String</code> Nazwa regionu tekstury, który ma się
     *            wyświetlić.
     */
    public Sprite(String id, Point point, Texture texture,
	    String textureRegionID)
    {
	super(id, point.x, point.y, texture.getTextureRegion(textureRegionID)
		.getSize().width, texture.getTextureRegion(textureRegionID)
		.getSize().height);
	this.setSpriteData(texture, textureRegionID);
    }

    /**
     * Tworzy dwuwymiarowy obraz z tekstury.
     * 
     * @param id
     *            <code>String</code> Nazwa obiektu.
     * @param x
     *            <code>float</code> Współrzędna X punktu zaczepienia.
     * @param y
     *            <code>float</code> Współrzędna Y punktu zaczepienia.
     * @param texture
     *            <code>Texture</code> Tekstura pobrana z TextureManager.
     * @param textureRegionID
     *            <code>String</code> Nazwa regionu tekstury, który ma się
     *            wyświetlić.
     */
    public Sprite(String id, float x, float y, Texture texture,
	    String textureRegionID)
    {
	super(id, x, y,
		texture.getTextureRegion(textureRegionID).getSize().width,
		texture.getTextureRegion(textureRegionID).getSize().height);
	this.setSpriteData(texture, textureRegionID);
    }

    /**
     * Tworzy dwuwymiarowy obraz z tekstury.
     * 
     * @param id
     *            <code>String</code> Nazwa obiektu.
     * @param point
     *            <code>Point</code> Punkt zaczepienia.
     * @param size
     *            <code>Size</code> Rozmiar obiektu.
     * @param texture
     *            <code>Texture</code> Tekstura pobrana z TextureManager.
     * @param textureRegionID
     *            <code>String</code> Nazwa regionu tekstury, który ma się
     *            wyświetlić.
     */
    public Sprite(String id, Point point, Size size, Texture texture,
	    String textureRegionID)
    {
	super(id, point.x, point.y, size.width, size.height);
	this.setSpriteData(texture, textureRegionID);
    }

    /**
     * Tworzy dwuwymiarowy obraz z tekstury.
     * 
     * @param id
     *            <code>String</code> Nazwa obiektu.
     * @param x
     *            <code>float</code> Współrzędna X punktu zaczepienia.
     * @param y
     *            <code>float</code> Współrzędna Y punktu zaczepienia.
     * @param size
     *            <code>Size</code> Rozmiar obiektu.
     * @param texture
     *            <code>Texture</code> Tekstura pobrana z TextureManager.
     * @param textureRegionID
     *            <code>String</code> Nazwa regionu tekstury, który ma się
     *            wyświetlić.
     */
    public Sprite(String id, float x, float y, Size size, Texture texture,
	    String textureRegionID)
    {
	super(id, x, y, size.width, size.height);
	this.setSpriteData(texture, textureRegionID);
    }

    /**
     * Tworzy dwuwymiarowy obraz z tekstury.
     * 
     * @param id
     *            <code>String</code> Nazwa obiektu.
     * @param x
     *            <code>float</code> Współrzędna X punktu zaczepienia.
     * @param y
     *            <code>float</code> Współrzędna Y punktu zaczepienia.
     * @param width
     *            <code>float</code> Szerokość.
     * @param height
     *            <code>float</code> Wysokość.
     * @param texture
     *            <code>Texture</code> Tekstura pobrana z TextureManager.
     * @param textureRegionID
     *            <code>String</code> Nazwa regionu tekstury, który ma się
     *            wyświetlić.
     */
    public Sprite(String id, float x, float y, float width, float height,
	    Texture texture, String textureRegionID)
    {
	super(id, x, y, width, height);
	this.setSpriteData(texture, textureRegionID);
    }

    private void setSpriteData(Texture texture, String textureRegionID)
    {
	this.mTexture = texture;
	this.mTextureRegion = texture.getTextureRegion(textureRegionID);
    }

    @Override
    public void draw(GL10 gl)
    {
	if (mVisible == false)
	    return;

	gl.glPushMatrix();
	gl.glEnable(GL10.GL_TEXTURE_2D);
	gl.glEnable(GL10.GL_BLEND);
	gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
	gl.glEnable(GL10.GL_ALPHA_BITS);
	gl.glColor4f(mColor.red, mColor.green, mColor.blue, mColor.alpha);
	gl.glBindTexture(GL10.GL_TEXTURE_2D, mTexture.getTexturePointer());
	gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
	gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
	gl.glFrontFace(GL10.GL_CW);
	gl.glVertexPointer(2, GL10.GL_FLOAT, 0, mVertexBuffer);
	gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0,
		mTextureRegion.getTextureBuffer());
	gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, mVerticesCount);
	gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
	gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
	gl.glDisable(GL10.GL_ALPHA_BITS);
	gl.glDisable(GL10.GL_TEXTURE_2D);
	gl.glPopMatrix();
    }

    @Override
    public void update(long elapsedTime)
    {
	// TODO Auto-generated method stub
    }

    // Extra class methods

    @Override
    public void setRegion(String regionID)
    {
	TextureRegion region = mTexture.getTextureRegion(regionID);

	if (region != null)
	{
	    this.mTextureRegion = region;
	}
    }

    @Override
    public TextureRegion getRegion()
    {
	return mTextureRegion;
    }

    @Override
    public void setTexture(Texture texture)
    {
	mTexture = texture;
    }

    @Override
    public Texture getTexture()
    {
	return mTexture;
    }

    @Override
    public void dispose()
    {
	mTexture.dispose();

	mTexture = null;
	mTextureRegion = null;

	super.dispose();
    }

}
